package pl.pw.gis.gc_sa.tests;

import static org.junit.Assert.assertEquals;

import java.util.Random;
import java.util.Vector;

import org.junit.BeforeClass;
import org.junit.Test;

import pl.pw.gis.gc_sa.algo.Cost;
import pl.pw.gis.gc_sa.algo.CostFromArticle;
import pl.pw.gis.gc_sa.data.Graph;
import pl.pw.gis.gc_sa.data.VertexChange;
import pl.pw.gis.gc_sa.utils.Utils;

/**
 * Klasa zawierajaca testy wykonywane przy pomocy biblioteki jUnit.
 * 
 * W tej klasie testowane poprawnosc wyliczania kosztu kolorowania grafu przez
 * klase CostFromArticle. Jako prawidlowy wynik wykorzystywany jest wynik
 * dostarczany przez metode naiveArticleCostFunction z klasy Utils (ktorej
 * poprawnosc jest testowana w osobnej klasie). Test polega na wylosowaniu 1000
 * zmian kolorowania (VertexChange) i sprawdzaniu czy po kazdej ze zmian koszt
 * zwracany przez obiekt klasy CostFromArticle jest rowny wartosci zwracanej
 * przez metoda naiveAritcleCostFunction
 * 
 * @author Lukasz
 * 
 */
public class ArticleCostFunctionsResultComparisonTest {
    static Random random;
    static Vector<Graph> graphs;

    int noIterationsPerGraph = 1000;

    @BeforeClass
    public static void initialize() throws Exception {
        random = new Random();
        graphs = new Vector<Graph>();

        graphs.add(Graph.createVPGraph(10, 1));
        graphs.add(Graph.createVPGraph(100, 1));
        graphs.add(Graph.createVPGraph(500, 1));
        graphs.add(Graph.createVPGraph(10, 0.5f));
        graphs.add(Graph.createVPGraph(100, 0.5f));
        graphs.add(Graph.createVPGraph(500, 0.5f));
    }

    @Test
    public void bigTest() throws Exception {

        for (Graph g : graphs) {
            int[] solution = initLegal(g.getVerticesCount());
            Cost cost2 = new CostFromArticle(g, solution);

            for (int i = 0; i < noIterationsPerGraph; i++) {
                int noColors = Utils.getColorsMap(solution).size();
                int id = random.nextInt(solution.length);
                int newColor = random.nextInt(noColors + 1);

                int tries = 0;
                while (newColor == solution[id]) {
                    newColor = random.nextInt(noColors + 1);
                    if (++tries == 10000) {
                        Utils.log("Tries over 10000");
                        return;
                    }
                }
                VertexChange vc = changeVertexColor(solution, id, newColor);
                int rightCost = Utils.naiveArticleCostFunction(solution, g);
                assertEquals(cost2.costAfterChange(vc), rightCost);
                cost2.applyChange(vc, rightCost);
            }

            solution = initSame(g.getVerticesCount());
            cost2 = new CostFromArticle(g, solution);

            for (int i = 0; i < noIterationsPerGraph; i++) {
                int noColors = Utils.getColorsMap(solution).size();
                int id = random.nextInt(solution.length);
                int newColor = random.nextInt(noColors + 1);

                int tries = 0;
                while (newColor == solution[id]) {
                    newColor = random.nextInt(noColors + 1);
                    if (++tries == 10000) {
                        Utils.log("Tries over 10000");
                        return;
                    }
                }
                VertexChange vc = changeVertexColor(solution, id, newColor);
                int rightCost = Utils.naiveArticleCostFunction(solution, g);
                assertEquals(cost2.costAfterChange(vc), rightCost);
                cost2.applyChange(vc, rightCost);
            }
        }
    }

    private int[] initLegal(int size) {
        int[] solution = new int[size];
        for (int i = 0; i < size; i++) {
            solution[i] = i;
        }
        return solution;
    }

    private int[] initSame(int size) {
        int[] solution = new int[size];
        for (int i = 0; i < size; i++) {
            solution[i] = 0;
        }
        return solution;
    }

    private VertexChange changeVertexColor(int[] solution, int id, int color) {
        int oldColor = solution[id];
        solution[id] = color;
        return new VertexChange(id, oldColor, color, true);
    }
}
